package main

import (
	"context"
	"fmt"
	pb "go_gprc/server/proto"
	"google.golang.org/grpc"
	"gorm.io/driver/mysql"
	"gorm.io/gorm"
	"gorm.io/gorm/logger"
	"log"
	"net"
)

var db *gorm.DB

type server struct {
	pb.UnimplementedUserServiceServer
}

func (UserModel) TableName() string {
	return "sys_user"

}

type UserModel struct {
	ID   int64  `json:"id" gorm:"primaryKey"`
	Name string `json:"name" gorm:"column:user_name;type:varchar(20);not null;comment:用户名;"`
	Age  int32  `json:"age" gorm:"column:age;size:10;comment:年龄;"`
}

func (s *server) ListUsers(ctx context.Context, req *pb.ListUsersRequest) (*pb.ListUsersResponse, error) {

	page := int(req.GetPage())
	pageSize := int(req.GetPageSize())

	var users []UserModel
	offset := (page - 1) * (pageSize)
	result := db.Offset(offset).Limit(pageSize).Find(&users)
	if result.Error != nil {
		return nil, result.Error
	}

	var pbUsers []*pb.User
	for _, user := range users {
		pbUsers = append(pbUsers, &pb.User{
			Id:   user.ID,
			Name: user.Name,
			Age:  user.Age,
		})
	}

	return &pb.ListUsersResponse{Users: pbUsers}, nil
}

func (s *server) CreateUser(ctx context.Context, req *pb.CreateUserRequest) (*pb.CreateUserResponse, error) {
	user := req.GetUser()
	newUser := UserModel{
		Name: user.GetName(),
		Age:  user.GetAge(),
	}

	result := db.Create(&newUser)
	if result.Error != nil {
		return nil, result.Error
	}

	return &pb.CreateUserResponse{User: &pb.User{
		Id:   newUser.ID,
		Name: newUser.Name,
		Age:  newUser.Age,
	}}, nil
}

func (s *server) GetUser(ctx context.Context, req *pb.GetUserRequest) (*pb.GetUserResponse, error) {
	var user UserModel
	result := db.First(&user, req.GetId())
	if result.Error != nil {
		return nil, result.Error
	}

	return &pb.GetUserResponse{User: &pb.User{
		Id:   user.ID,
		Name: user.Name,
		Age:  user.Age,
	}}, nil
}

func (s *server) UpdateUser(ctx context.Context, req *pb.UpdateUserRequest) (*pb.UpdateUserResponse, error) {
	var user UserModel

	result := db.First(&user, req.GetId())

	if result.Error != nil {
		return nil, result.Error
	}

	db.Model(&user).Updates(UserModel{Name: req.GetName(), Age: req.GetAge()})
	return &pb.UpdateUserResponse{User: &pb.User{
		Id:   user.ID,
		Name: user.Name,
		Age:  user.Age,
	}}, nil
}

func (s *server) DeleteUser(ctx context.Context, req *pb.DeleteUserRequest) (*pb.DeleteUserResponse, error) {
	var user UserModel
	result := db.First(&user, req.GetId())
	if result.Error != nil {
		return nil, result.Error
	}
	db.Delete(&user)
	return &pb.DeleteUserResponse{User: &pb.User{
		Id:   user.ID,
		Name: user.Name,
		Age:  user.Age,
	}}, nil
}

func ConnectDB() {
	username := "root"
	password := "chestnutaxaz"
	host := "127.0.0.1"
	port := "3306"
	database := "crud"
	url := fmt.Sprintf("%s:%s@tcp(%s:%s)/%s?charset=utf8mb4&parseTime=True&loc=Local", username, password, host, port, database)
	var mysqlLogger logger.Interface
	mysqlLogger = logger.Default.LogMode(logger.Info)
	var err error
	if db, err = gorm.Open(mysql.Open(url), &gorm.Config{Logger: mysqlLogger}); err != nil {
		log.Fatalf("Failed to connect to the database: %v", err)
	}
	fmt.Println("Connected to the database successfully.")
}

func main() {
	ConnectDB()
	err := db.AutoMigrate(&UserModel{})
	if err != nil {
		fmt.Println("映射表错误")
		return
	}

	lis, err := net.Listen("tcp", ":50055")
	if err != nil {
		log.Fatalf("failed to listen: %v", err)
	}

	s := grpc.NewServer()
	pb.RegisterUserServiceServer(s, &server{})

	fmt.Println("gRPC server is running on port :50055")
	if err := s.Serve(lis); err != nil {
		log.Fatalf("failed to serve: %v", err)
	}
}
